package com.onpositive.page.pagerendering;

import java.io.IOException;
import java.io.Reader;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import org.eclipse.jface.text.Document;

import com.onpositive.page.core.wikihelper.DocumentWrapper;
import com.onpositive.page.core.wikihelper.FontStyleManager;
import com.onpositive.page.core.wikihelper.WebImageManager;
import com.onpositive.page.core.wikihelper.WebLayerManager;
import com.onpositive.richtext.model.BasePartition;
import com.onpositive.richtext.model.BasePartitionLayer;
import com.onpositive.richtext.model.HRPartition;
import com.onpositive.richtext.model.ImagePartition;
import com.onpositive.richtext.model.LinkPartition;
import com.onpositive.richtext.model.RegionPartition;
import com.onpositive.richtext.model.meta.ITextDocument;
import com.onpositive.richtexteditor.io.ILineInformationProvider;
import com.onpositive.richtexteditor.io.ModelBasedLineInformationProvider;
import com.onpositive.richtexteditor.io.html.HTMLSerializer;
import com.onpositive.richtexteditor.io.html.ISerializationHelper;
import com.onpositive.richtexteditor.model.ISimpleRichTextModel;
import com.onpositive.richtexteditor.wikitext.io.DefaultWikitextLoader;

public class WikiRendererImpl {

	private static final class UpdatedSerializer extends HTMLSerializer {
		private UpdatedSerializer(BasePartitionLayer layer, ITextDocument doc,
				ILineInformationProvider iLineInformationProvider) {
			super(layer, doc, iLineInformationProvider);
		}

		LinkedHashMap<String, String> map = new LinkedHashMap<String, String>();

		@Override
		protected String getParagraphStartString(int lineIdx) {
			return "<p ";
		}
		
		protected void defineNumberedListsEnds() {
			final int numberOfLines = doc.getNumberOfLines();
			for (int i = 0; i < numberOfLines; i++) {
				final int bulletType = provider.getBulletType(i);
				if (bulletType != ILineInformationProvider.NONE_BULLET)
				/*if (bulletType == ILineInformationProvider.NUMBER_BULLET
						|| bulletType == ILineInformationProvider.LETTER_BULLET
						|| bulletType == ILineInformationProvider.ROMAN_BULLET
						|| bulletType == ILineInformationProvider.EXPLICIT_BULLET)*/ // (was
																					// ST.BULLET_TEXT
																					// |
																					// ST.BULLET_NUMBER)
				{
					int curBulletId = provider.getBulletIdForLine(i);
					listsIndents.put(curBulletId, provider.getLineIndent(i));
					int j = i;
					int last = j;
					while (++j < numberOfLines) {
						if (provider.getBulletType(j)==ILineInformationProvider.NONE_BULLET){
							if (bulletType==ILineInformationProvider.SIMPLE_BULLET){
								last = j-1;
								break;
							}
						}
						if (provider.getBulletIdForLine(j) == curBulletId)
							last = j;
					}
					int k = last + 1;
					for (;k < numberOfLines && provider.getLineIndent(k) > provider.getLineIndent(i) && provider.getBulletType(k) != ILineInformationProvider.NONE_BULLET; k++);
					last = k--;
					if (!listsEnds.containsKey(last))
						listsEnds.put(last, curBulletId);
				}
			}
		}


		protected void closeListsIfNeeded(int lineIndex, StringBuilder sb,
				boolean lastLine) {
			
			if (!lastLine) {
				final Integer curEnd = listsEnds.get(lineIndex);
				if (curEnd != null) {
					int level = listsIndents.get(curEnd);
					level = Math.max(level, 1);
					sb.append(closeLists(level));					
				}
				
			} else
				while (openedTags.size() > 0) {
					Integer tag = openedTags.pop();
					if (tag == ILineInformationProvider.SIMPLE_BULLET)
						sb.append(getBulletedListCloseString());
					else if (tag == ILineInformationProvider.LETTER_BULLET
							|| tag == ILineInformationProvider.NUMBER_BULLET
							|| tag == ILineInformationProvider.ROMAN_BULLET)
						sb.append(getNumberedListCloseString());
				}
		}

		protected String getFileEndString() {
			return "";
		}

		@Override
		protected String getFileStartString() {
			return "";
		}

		@Override
		protected String getRegionString(RegionPartition partition) {
			String contentType = partition.getContentType();
			if (contentType.equals("#!html")) {
				return partition.getContent();
			}
			
			if (contentType.startsWith("#!div:")) {
				String substring = contentType.substring("#!div:".length());
				String string = map.get(substring);
				if (string!=null){
					map.put(substring, string+partition.getContent());
				}
				else{
					map.put(substring, partition.getContent());
				}
				return "";
			}
			map.put("extras","<script type=\"text/javascript\" src=\"/scripts/sh/shCore.js\"></script>\r\n" + 
					"<script type=\"text/javascript\" src=\"/scripts/sh/shBrushJScript.js\"></script>\r\n" + 
					"<script type=\"text/javascript\" src=\"/scripts/sh/shBrushJava.js\"></script>\r\n" + 
					"<script type=\"text/javascript\" src=\"/scripts/sh/shBrushXml.js\"></script>\r\n" +					
					"<script type=\"text/javascript\" src=\"/scripts/sh/shBrushCss.js\"></script>\r\n"+
					"<link href=\"/styles/shCore.css\" rel=\"stylesheet\" type=\"text/css\" />\r\n" + 
					"<link href=\"/styles/shThemeDefault.css\" rel=\"stylesheet\" type=\"text/css\" />");
			return "<pre class=\"brush: "+contentType.substring(2)+"\">"+partition.getContent()+"</pre>";			
		}

		protected String getSerializedPartOfLine(int lineIndex, int offset,
				int length, boolean appendParagraphs) {
			final int bulletType = provider.getBulletType(lineIndex);

			if (bulletType != ILineInformationProvider.NONE_BULLET) {
				String s1="";
				
				String q = super.getSerializedPartOfLine(lineIndex, offset,
						length, false);
				if (bulletType==ILineInformationProvider.SIMPLE_BULLET){
					if (openedTags.indexOf(ILineInformationProvider.SIMPLE_BULLET)==-1){
						s1="<ul>";
						openedTags.add(ILineInformationProvider.SIMPLE_BULLET);
					}
				}
				StringBuilder bld = new StringBuilder();
				closeListsIfNeeded(lineIndex, bld, false);
				String s = bld.toString();
				return s1+q + s;
			}

			BasePartition startPartition = (BasePartition) curLayer
					.getPartitionAtOffset(offset);
			if (startPartition instanceof RegionPartition){
				return super.getSerializedPartOfLine(lineIndex, offset, length,
						false);
			}
			if (startPartition.getFontDataName().startsWith("Header")) {
				return super.getSerializedPartOfLine(lineIndex, offset, length,
						false);
			}
			return super.getSerializedPartOfLine(lineIndex, offset, length,
					true);
		}
		
		@Override
		protected String getLinkEndString() {
			if (insideEscapedLink){
				insideEscapedLink=false;
				return "";
			}
			return super.getLinkEndString();
		}
		boolean insideEscapedLink;
		
		@Override
		protected String getLinkStartString(LinkPartition partition) {
			if (partition.getStyle()==LinkPartition.ESCAPED){
				insideEscapedLink=true;
				return "";
			}
			return super.getLinkStartString(partition);
		}
		
		@Override
		protected String getHRString(HRPartition partition) {
			// TODO Auto-generated method stub
			return super.getHRString(partition);
		}
		
		@Override
		protected String getImageStr(ImagePartition partition) {
			// TODO Auto-generated method stub
			return super.getImageStr(partition);
		}

		@Override
		public String getSerializedLine(int lineNum) {
			return super.getSerializedLine(lineNum);
		}

		protected String getFontStyleOpeningTag(BasePartition partition) {
			if (partition.getFontDataName().startsWith("Header")) {
				return "<h"
						+ partition.getFontDataName().charAt(
								partition.getFontDataName().length() - 1) + ">";
			}
			return super.getFontStyleOpeningTag(partition);

		}

		@Override
		protected java.lang.String getFontStyleClosingTag(
				BasePartition partition) {
			if (partition.getFontDataName().startsWith("Header")) {
				return "</h"
						+ partition.getFontDataName().charAt(
								partition.getFontDataName().length() - 1) + ">";
			}
			return super.getFontStyleClosingTag(partition);
		}
	}

	

	public static String renderContent(Reader resource,Map<String,String> addition) {
		DocumentWrapper d = new DocumentWrapper(new Document());
		ISimpleRichTextModel parse;
		try {
			parse = new DefaultWikitextLoader(d).parse(resource);
		} catch (IOException e) {
			e.printStackTrace();
			return e.getMessage();
		}

		ModelBasedLineInformationProvider modelBasedLineInformationProvider = new ModelBasedLineInformationProvider(
				parse);
		BasePartitionLayer basePartitionLayer = new BasePartitionLayer();
		List<BasePartition> partitions = parse.getPartitions();
	
		for( BasePartition p : partitions){
			if(p instanceof RegionPartition){
				break;
			}
		}
		
		basePartitionLayer.getStorage().setPartitions(partitions);
		
		WebLayerManager l = new WebLayerManager(d, new FontStyleManager(),
				new WebImageManager(), basePartitionLayer);
		basePartitionLayer.setManager(l);
		UpdatedSerializer s = new UpdatedSerializer(basePartitionLayer, d,
				modelBasedLineInformationProvider);
		s.setHelper(new ISerializationHelper() {

			public String getLinkURL(LinkPartition partition) {
				if (partition.getStyle()==LinkPartition.ESCAPED){
					return null;
				}
				String url = partition.getUrl();
				if (url.startsWith("wiki://")) {
					return "/" + url.substring("wiki://".length());
				}
				return url;
			}
			
			public String getImageLocation(ImagePartition partition) {
				String url = partition.getImageFileName();
				if (url.startsWith("wiki://")) {
					return url.substring("wiki://".length());
				}
				return url;
			}
			
			public String getAdditionPartitionSuffix(BasePartition partition) {
				return null;
			}

			public String getAdditionPartitionPrefix(BasePartition partition) {
				return null;
			}
		});		
		String serializeAllToStr = s.serializeAllToStr();
		addition.putAll(s.map);
		return serializeAllToStr;
	}

}
